package com.sharp;

import java.io.File;
import java.io.FilenameFilter;

import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;

import com.sharp.core.GraphicScene;
import com.sharp.core.graphics.Color;
import com.sharp.core.graphics.Graphic;
import com.sharp.core.graphics.Light;
import com.sharp.core.graphics.gl.OpenGLGraphic;
import com.sharp.core.math.Matrix;
import com.sharp.core.math.Transformations;
import com.sharp.core.math.Vec3;
import com.sharp.core.math.primitives.Sphere;
import com.sharp.core.raytrace.Camera;
import com.sharp.core.raytrace.ObjectHolder;
import com.sharp.core.raytrace.PerspectiveRayFactory;
import com.sharp.core.raytrace.PrimitiveHolder;
import com.sharp.core.raytrace.RayFactory;
import com.sharp.core.raytrace.RayTracer;
import com.sharp.core.raytrace.VoxelTracer;
import com.sharp.core.raytrace.shading.DiffuseShading;
import com.sharp.core.raytrace.shading.FlatShading;
import com.sharp.core.raytrace.shading.Shading;
import com.sharp.core.utils.Vars;
import com.sharp.core.voxel.ListVoxelScene;
import com.sharp.core.voxel.Voxel;
import com.sharp.core.voxel.VoxelArray;
import com.sharp.core.voxel.VoxelLoader;
import com.sharp.core.voxel.GridVoxelScene;
import com.sharp.core.voxel.VoxelObject;
import com.sharp.core.voxel.resource.VoxelResource;

public class TestScene extends GraphicScene {

	public static final int W = 640;
	public static final int H = 480;

	private Graphic g;
	private RayFactory caster;
	private Camera cam;
	private Shading shading;
	
	private RayTracer tracer;
	private VoxelTracer tracer2;
	
	public TestScene(ObjectHolder h, int tick) {
		super(h, tick);
	}
	
	
	@Override
	protected void click(int x, int y, int btn) {
	}

	@Override
	protected void mouseWheel(int d) {
	}

	
	@Override
	public void deInit() {
	}

	@Override
	public boolean init() throws Exception {
		g = new OpenGLGraphic();
		//g = new Java2DGraphic();
		
		g.init(W, H, 32);
		//Mouse.setGrabbed(true);
		
		cam = new Camera(0, 0, W, H, 90);

		caster = new PerspectiveRayFactory(cam);
		
		shading = new DiffuseShading();
		//shading = new SimpleShading();
		
		getObjHolder().setAmbientCoefficient(0.01f);
		
		for ( int i = 0; i < 10; ++i ) {
			Sphere s = new Sphere((float)Math.random()*2);
			s.getMaterial().setColor( Color.Random() );
			s.getMaterial().setDiffuse((float)Math.random()+0.5f);
			s.getMaterial().setReflectivity(1);
			s.getMaterial().setTransmittivity((float)Math.random());
			s.setPos(new Vec3((float)Math.random()*0, (float)Math.random()*0, (float)Math.random()*50));
			getObjHolder().addObject(s);
		}
		
		Sphere s = new Sphere();
		s.getMaterial().setColor(Color.RED);
		s.getMaterial().setReflectivity(0.5f);
		s.getMaterial().setTransmittivity((float)Math.random());
		s.setRadius(3);
		s.setPos(new Vec3(0, 5, 10));
		getObjHolder().addObject(s);
		
		Light l0 = new Light();
		l0.getMaterial().setColor(Color.WHITE);
		l0.setRadius(3);
		l0.setPos(new Vec3(10, 5, 10));
		getObjHolder().addLight(l0);
		
		Light l1 = new Light();
		l1.getMaterial().setColor(Color.GREEN);
		l1.setRadius(0.3f);
		l1.setPos(new Vec3(-7, 0, 5));
		getObjHolder().addLight(l1);
		
		tracer = new RayTracer(cam, caster, shading, (PrimitiveHolder) getObjHolder());
		
		//GridVoxelScene scene = new GridVoxelScene(100, 100, 100, 10);
		ListVoxelScene scene = new ListVoxelScene();
		
		/*File dataDir = new File("data");
		for ( File file : dataDir.listFiles(new FilenameFilter() {
			
			@Override
			public boolean accept(File dir, String name) {
				return name.endsWith(".vox");
			}
		})) {
			VoxelResource dat = VoxelLoader.load(file);
			scene.addObject(new VoxelObject( dat.convertToVoxelArray() ), (int)(Math.random()*100), 
					(int)(Math.random()*100), (int)(Math.random()*100));
		}*/
		VoxelResource dat = VoxelLoader.get("data/desklamp.vox");
		//dat = VoxelLoader.load("data/coin.vox");
		//dat = VoxelLoader.load("data/worm.vox");
		//dat = VoxelLoader.load("data/duke.vox");
		//dat = VoxelLoader.load("data/knight.vox");
		scene.addObject(new VoxelObject( dat.convertToVoxelArray() ), 0, 0, 30);
		
		VoxelArray vox = new VoxelArray(1, 1, 1);
		vox.setVoxel(0, 0, 0, new Voxel(new Color(Color.RED)));
		VoxelObject obj = new VoxelObject(vox);
		/*scene.addObject(obj, 0, 0, 0);
		scene.addObject(obj, 99, 0, 0);
		scene.addObject(obj, 0, 99, 0);
		scene.addObject(obj, 0, 0, 99);
		scene.addObject(obj, 99, 99, 0);
		scene.addObject(obj, 0, 99, 99);
		scene.addObject(obj, 99, 0, 99);
		scene.addObject(obj, 99, 99, 99);*/
		scene.addObject(obj, 6, 6, 10);
		
		cam.setPos(new Vec3(5.5f, 5.5f, 5.5f));
		
		tracer2 = new VoxelTracer(cam, new PerspectiveRayFactory(cam), new FlatShading(), scene);
		//tracer2.render();
		
		Vars.set(Vars.INTERSECT_PER_FRAME, 0);
		return true;
	}

	@Override
	protected boolean isActive() {
		return isActive();
	}

	@Override
	protected boolean isCloseRequested() {
		return Display.isCloseRequested();
	}

	@Override
	protected void logic() {
		Keyboard.poll();
		if ( Keyboard.isKeyDown(Keyboard.KEY_W) ) {
			cam.forward(1f);
		}
		else if ( Keyboard.isKeyDown(Keyboard.KEY_S) ) {
			cam.forward(-1f);
		}
		
		if ( Keyboard.isKeyDown(Keyboard.KEY_A) ) {
			cam.strafe(-1f);
		}
		else if ( Keyboard.isKeyDown(Keyboard.KEY_D) ) {
			cam.strafe(1f);
		}
		if ( Keyboard.isKeyDown(Keyboard.KEY_Q) ) {
			Mouse.setGrabbed(true);
		}
		if ( Keyboard.isKeyDown(Keyboard.KEY_E) ) {
			Mouse.setGrabbed(false);
		}
		
		int dx = Mouse.getDX();
		int dy = Mouse.getDY();
		Matrix rightLeft = Transformations.rotateAboutY(dx/10);
		Matrix upDown = Transformations.rotateAboutX(dy/10);
		Matrix m = rightLeft.multiply(upDown);
		
		cam.rotate( m );
	}

	@Override
	protected void render() {
		//tracer.render();
		tracer2.render();
		//Graphic.instance().clean();
		((OpenGLGraphic) g).drawBackBuffer();
		Graphic.instance().update();
		Display.setTitle(""+getPerfomance()+", Cam: " + cam.toString() + ", Grid per frame: " +Vars.g);
		//Vars.set(Vars.INTERSECT_PER_FRAME, 0);
		Vars.g = 0;
	}
}
